
package com.treeman.navi.rest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;

import android.app.ProgressDialog;
import android.os.Handler;
import android.os.Message;
import android.util.Log;


public class RestClient implements Runnable
{

    public static final String TAG = "RestClient";

    private ArrayList<NameValuePair> headers;
    private ArrayList<NameValuePair> params;

    private String url;
    private String message;
    private String response;

    private int responseCode;

    private Handler handler;

    private int timeoutConnection = 3000;
    private int timeoutData = 3000;

    private Thread runnableThread;

    private RequestMethod method;

    private HttpClient httpClient;

    private ProgressDialog progressDialog;


    public enum HttpConnectionStatus
    {
	START, SUCCESS, ERROR, TIMEOUT
    }

    public static enum RequestMethod
    {
	GET, POST, PUT, DELETE
    }


    public String getResponse()
    {
	return response;
    }

    public int getResponseCode()
    {
	return responseCode;
    }

    public String getMessage()
    {
	return message;
    }

    public int getTimeoutData()
    {
	return timeoutData;
    }

    public void setTimeoutData(int timeoutData)
    {
	this.timeoutData = timeoutData;
    }

    public int getTimeoutConnection()
    {
	return timeoutConnection;
    }

    public void setTimeoutConnection(int timeoutConnection)
    {
	this.timeoutConnection = timeoutConnection;
    }

    public RestClient(String url, Handler handler)
    {
	this.url = url;
	params = new ArrayList<NameValuePair>();
	headers = new ArrayList<NameValuePair>();

	this.handler = handler;
    }

    public void AddParam(String name, String value)
    {
	params.add(new BasicNameValuePair(name, value));
    }

    public void AddHeader(String name, String value)
    {
	headers.add(new BasicNameValuePair(name, value));
    }

    public void Execute(RequestMethod method) throws Exception
    {
	this.method = method;

	if (progressDialog != null) progressDialog.show();

	ConnectionManager.getInstance().push(this);
    }

    private static String convertStreamToString(InputStream is)
    {

	BufferedReader reader = new BufferedReader(new InputStreamReader(is));
	StringBuilder sb = new StringBuilder();

	String line = null;
	try
	{
	    while ((line = reader.readLine()) != null)
	    {
		sb.append(line);
	    }
	}
	catch (IOException e)
	{
	    e.printStackTrace();
	}
	finally
	{
	    try
	    {
		is.close();
	    }
	    catch (IOException ex)
	    {
		Log.e(TAG, " RestClient error : ", ex);
	    }
	}
	return sb.toString();
    }

    public String toString()
    {
	return "";
    }

    public String getJSON()
    {

	if (response.length() > 0)
	{
	    return response;
	}

	return new String();

    }

    @Override
    public void run()
    {
	HttpParams httpParameters = new BasicHttpParams();
	HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
	HttpConnectionParams.setSoTimeout(httpParameters, timeoutData);

	httpClient = new DefaultHttpClient(httpParameters);
	handler.sendMessage(Message.obtain(handler, HttpConnectionStatus.START.ordinal(), this));

	try
	{
	    HttpResponse httpResponse = null;

	    switch (method)
	    {
	    // GET
		case GET:
		{
		    String combinedParams = "";
		    if (!params.isEmpty())
		    {
			combinedParams += "?";
			for (NameValuePair p : params)
			{
			    String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(), "UTF-8");
			    if (combinedParams.length() > 1)
			    {
				combinedParams += "&" + paramString;
			    }
			    else
			    {
				combinedParams += paramString;
			    }
			}
		    }

		    HttpGet getRequest = new HttpGet(url + combinedParams);
		    // add headers
		    for (NameValuePair h : headers)
		    {
			getRequest.addHeader(h.getName(), h.getValue());
		    }

		    httpResponse = httpClient.execute(getRequest);

		    break;
		}
		// END GET
		// POST
		case POST:
		{
		    HttpPost postRequest = new HttpPost(url);

		    // add headers
		    for (NameValuePair h : headers)
		    {
			postRequest.addHeader(h.getName(), h.getValue());
		    }

		    if (!params.isEmpty())
		    {
			postRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
		    }

		    httpResponse = httpClient.execute(postRequest);

		    break;
		}
		// END POST
		// DELETE
		case DELETE:
		{
		    HttpDelete deleteRequest = new HttpDelete(url);

		    httpResponse = httpClient.execute(deleteRequest);

		    break;
		}
		// END PUT
		case PUT:
		{
		    HttpPut putRequest = new HttpPut(url);

		    httpResponse = httpClient.execute(putRequest);

		    break;
		}
		// END PUT
	    }

	    responseCode = httpResponse.getStatusLine().getStatusCode();
	    message = httpResponse.getStatusLine().getReasonPhrase();

	    HttpEntity entity = httpResponse.getEntity();

	    processEntity(entity);

	}
	catch (ConnectTimeoutException ex)
	{
	    Log.e(TAG, " Connection timeout!");
	}
	catch (Exception ex)
	{
	    handler.sendMessage(Message.obtain(handler, HttpConnectionStatus.ERROR.ordinal(), this));
	    Log.e(TAG, " Connection error : ", ex);
	}
	finally
	{
	    if (progressDialog != null) progressDialog.dismiss();
	}
	ConnectionManager.getInstance().didComplete(this);
    }

    private void processEntity(HttpEntity entity)
    {
	try
	{
	    InputStream instream = entity.getContent();

	    response = convertStreamToString(instream);

	    instream.close();

	    handler.sendMessage(Message.obtain(handler, HttpConnectionStatus.SUCCESS.ordinal(), this));

	    return;
	}
	catch (ClientProtocolException ex)
	{
	    httpClient.getConnectionManager().shutdown();
	    Log.e(TAG, " RestClient error : ", ex);
	}
	catch (IOException ex)
	{
	    httpClient.getConnectionManager().shutdown();
	    Log.e(TAG, " RestClient error : ", ex);
	}
	catch (Exception ex)
	{
	    httpClient.getConnectionManager().shutdown();
	    Log.e(TAG, " RestClient error : ", ex);
	}
    }

    public void setProgressDialog(ProgressDialog progressDialog)
    {
	this.progressDialog = progressDialog;
    }
}
